#include "StdAfx.h"
#include "DrumFactory.h"
#include "audio\DirSoundSource.h"
#include "WavePlayer.h"
#include "Notes.h"

#include <cmath>

short RngBound(double d)
{
    if(d < -32768)
        return -32768;
    else if(d > 32767)
        return 32767;

    return (short)d;
}


CDrumFactory::CDrumFactory(void)
{
	LoadFile("bass1.wav");
	LoadFile("bass2.wav");
	LoadFile("bass3.wav");
	
	LoadFile("tom1.wav");
	LoadFile("tom2.wav");
	LoadFile("tom3.wav");
	LoadFile("tom4.wav");
	LoadFile("tom5.wav");
	LoadFile("tom6.wav");
	LoadFile("tom7.wav");
	LoadFile("tom8.wav");

	LoadFile("cymbal1.wav");
	LoadFile("cymbal2.wav");
	LoadFile("cymbal3.wav");
	LoadFile("cymbal4.wav");
	LoadFile("cymbal5.wav");

	LoadFile("snare1.wav");
	LoadFile("snare2.wav");
	LoadFile("snare3.wav");
	LoadFile("snare4.wav");
	LoadFile("snare5.wav");

	LoadFile("hihat1.wav");

	m_pitch = 1.;
}

CDrumFactory::~CDrumFactory(void)
{
}


CDrumSynth *CDrumFactory::CreateInstrument()
{
    CDrumSynth *instrument = new CDrumSynth();
    instrument->GetPlayer()->SetSamples(&m_wavetable[m_holder][0], (int)m_wave.size());

    return instrument;
}

void CDrumFactory::SetNote(CNote *note)
{
    // Get a list of all attribute nodes and the
    // length of that list
    CComPtr<IXMLDOMNamedNodeMap> attributes;
    note->Node()->get_attributes(&attributes);
    long len;
    attributes->get_length(&len);

    // Loop over the list of attributes
    for(int i=0;  i<len;  i++)
    {
        // Get attribute i
        CComPtr<IXMLDOMNode> attrib;
        attributes->get_item(i, &attrib);

        // Get the name of the attribute
        CComBSTR name;
        attrib->get_nodeName(&name);

        // Get the value of the attribute.  A CComVariant is a variable
        // that can have any type. It loads the attribute value as a
        // string (UNICODE), but we can then change it to an integer 
        // (VT_I4) or double (VT_R8) using the ChangeType function 
        // and then read its integer or double value from a member variable.
        CComVariant value;
        attrib->get_nodeValue(&value);

		if(name == "note")
        {
			if(!lstrcmpW(value.bstrVal,L"bass1"))
			{
				m_holder = 0;
				m_wave = m_wavetable[0];
			}
			else if(!lstrcmpW(value.bstrVal,L"bass2"))
			{
				m_holder = 1;
				m_wave = m_wavetable[1];
			}
			else if(!lstrcmpW(value.bstrVal,L"bass3"))
			{
				m_holder = 2;
				m_wave = m_wavetable[2];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom1"))
			{
				m_holder = 3;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom2"))
			{
				m_holder = 4;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom3"))
			{
				m_holder = 5;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom4"))
			{
				m_holder = 6;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom5"))
			{
				m_holder = 7;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom6"))
			{
				m_holder = 8;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom7"))
			{
				m_holder = 9;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"tom8"))
			{
				m_holder = 10;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"cymbal1"))
			{
				m_holder = 11;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"cymbal2"))
			{
				m_holder = 12;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"cymbal3"))
			{
				m_holder = 13;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"cymbal4"))
			{
				m_holder = 14;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"cymbal5"))
			{
				m_holder = 15;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"snare1"))
			{
				m_holder = 16;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"snare2"))
			{
				m_holder = 17;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"snare3"))
			{
				m_holder = 18;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"snare4"))
			{
				m_holder = 19;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"snare5"))
			{
				m_holder = 20;
				m_wave = m_wavetable[m_holder];
			}
			else if(!lstrcmpW(value.bstrVal,L"hihat"))
			{
				m_holder = 21;
				m_wave = m_wavetable[m_holder];
			}

        }
/*		if(name == "pitch")
		{
			value.ChangeType(VT_R8);
			m_pitch = value.dblVal;
		}*/

    }

}

bool CDrumFactory::LoadFile(const char *filename)
{
    m_wave.clear();

    CDirSoundSource m_file;
    if(!m_file.Open(filename))
    {
        CString msg = L"Unable to open audio file: ";
        msg += filename;
        AfxMessageBox(msg);
        return false;
    }

    for(int i=0;  i<m_file.NumSampleFrames();  i++)
    {
		double factor;
        short frame[2];
        m_file.ReadFrame(frame);
		if((double(i)/double(m_file.NumSampleFrames())) < 0.05)
		{
			factor = (double(i)/double(m_file.NumSampleFrames())) * 20;
			m_wave.push_back(frame[0]*factor);
		}
	/*	else if((double(i)/double(m_file.NumSampleFrames())) < 0.15)
		{
			factor = ((double(i)/double(m_file.NumSampleFrames())) - 0.10) * 2;
			m_wave.push_back(frame[0]*(1.-factor));
		}*/
		else if((double(i)/double(m_file.NumSampleFrames())) > 0.50)
		{
			factor = ((double(i)/double(m_file.NumSampleFrames())) - 0.50 ) * 2.0;
			m_wave.push_back(frame[0]*(1.-factor));
		}
		else
		{
			m_wave.push_back(frame[0]);
		}
    }

	m_wavetable.push_back(m_wave);

    m_file.Close();
    return true;
}

bool CDrumFactory::SynthDrum()
{
    m_wave.clear();

	int amp = 12800;
	int freq = 1000;

	for(double t = 0; t < 1; t += 1. / 44100.)
	{
		short n = (amp * sin(2 * PI * freq * t));
		amp = 1000 * (1-t/44100);
		m_wave.push_back(n);
	}

	m_wavetable.push_back(m_wave);

    return true;
}